home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / MISC / MAG08.ZIP / MAG08.TXT < prev    next >
Encoding:
Text File  |  1996-04-30  |  77.8 KB  |  1,713 lines

  1. Spellcaster presents:
  2.  
  3.  
  4. TTTTTTTTTT HH      HH EEEEEEEEEE    MM      MM    AAAA     GGGGGGGGG
  5.     TT     HH      HH EE            MMM    MMM   AA  AA   GG
  6.     TT     HH      HH EE            MM M  M MM  AA    AA  GG  
  7.     TT     HHHHHHHHHH EEEEEE        MM  MM  MM  AAAAAAAA  GG   
  8.     TT     HH      HH EE            MM      MM  AA    AA  GG    GGGG
  9.     TT     HH      HH EE            MM      MM  AA    AA  GG      GG
  10.     TT     HH      HH EEEEEEEEEE    MM      MM  AA    AA   GGGGGGGG
  11.  
  12.                                                         Issue 8
  13.                                                         26-4-96
  14.  
  15.  
  16. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  17.  
  18.  
  19.   Index:
  20.  
  21.         1. Introduction
  22.           1.1. About the magazine
  23.           1.2. About the author
  24.           1.3. Distribution
  25.           1.4. Contribuitions
  26.           1.5. Hellos and greets
  27.         2. Mailroom
  28.         3. Coding sites
  29.         4. Designing a text adventure - Part I
  30.           4.1. Plot creation
  31.           4.2. Plotline
  32.           4.3. Map creation
  33.           4.4. Getting started
  34.         5. Our friend, the pointer - Part III
  35.         6. How to make a cool starfield
  36.         7. Sprites Part I - Introduction
  37.           7.1. Generating images
  38.           7.2. Killing an image
  39.           7.3. Displaying an image
  40.           7.4. Clipping
  41.           7.5. Saving to the disk
  42.           7.6. Loading from the disk
  43.         8. Graphics Part VII - Scrolling Part II
  44.           8.1. Tile Scrolling
  45.           8.2. Parallax Scrolling
  46.           8.3. Partial Scrolls
  47.         9. Hints and tips
  48.        10. Points of view
  49.        11. The adventures of Spellcaster, part 8
  50.  
  51.  
  52. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  53.  
  54.  
  55.   1. Introduction
  56.  
  57.     1.1. About the magazine
  58.  
  59.     Welcome to number 8 of 'The Mag', brought to you, as usual, by Spellcaster,
  60.   alias Diogo de Andrade. This is another big issue, so scream in joy ! :)
  61.     I'm very happy !! This is the first issue to feature an article I didn't
  62.   write !! That article is a little bit different from the usual articles. It's
  63.   about were can you get info on programming and other stuff coding-related.
  64.   It was writen by Scorpio (another portuguese dude !!), one of the people
  65.   that most support 'The Mag'... He is also the person that stands all of my
  66.   questions in the MOO I'm trying now... Thanks, man, for beeing there... ;)
  67.     Also, a little add... I'm trying to change the logo on top, the one that
  68.   says 'THE MAG', but my ANSI art sucks !! In fact, all my art sucks !!! I was
  69.   born to code... :) So, if anyone out there wants to do a better logo for me,
  70.   go ahead !!! NOTE- No strange codes, just plain ASCII chars... Not even
  71.   ASCII-E characters, because I use (and sometimes write) this in a UNIX
  72.   machine, and I don't know how to configure the simbols on the screen... :(
  73.  
  74.     This magazine is dedicated to all the programmers and would-be programmers
  75.   out there, especially to those that can't access the Net easily to get
  76.   valuable information, to those who wish to learn how to program anything,
  77.   from demos to games, passing through utilities and all sort of thing your
  78.   mind can think of, and to those that can't find the right information.
  79.  
  80.     When you read this magazine, I'll assume some things. First, I assume you
  81.   have Borland's Turbo Pascal, version 6 and upwards (and TASM for the assembly
  82.   tutorials). I'll also think you have a 80386 (or 386 for short; a 486 would
  83.   be even better), a load of patience and a sense of humor. This last is almost
  84.   essencial, because I don't receive any money for doing this, so I must have
  85.   fun doing it. I will also take for certain you have the 9th grade (or
  86.   equivelent). Finally, I will assume that you have the last issues of
  87.   'The Mag', and that you have grasped the concepts I tried to transmit. If
  88.   you don't have the issues, you can get them by mail, writing to one of the
  89.   adresses shown below (Snail mail and Email).
  90.  
  91.     As I stated above, this magazine will be made especially for those who don't
  92.   know where to get information, or want it all in the same place, and to those
  93.   who want to learn how to program, so I'll try to build knowledge, building up
  94.   your skills issue by issue. If you sometimes fail to grasp some concept, don't
  95.   despair; try to work it out.
  96.     That's what I did... Almost everything I know was learnt from painfull
  97.   experience. If you re-re-re-read the article, and still can't understand it,
  98.   just drop a line, by mail, or just plain forget it. Most of the things I 
  99.   try to teach here aren't linked to each other (unless I say so), so if you
  100.   don't understand something, skip it and go back to it some weeks later. It
  101.   should be clearer for you then. Likewise, if you see any terms or words you 
  102.   don't understand, follow the same measures as before.
  103.  
  104.     Ok, as I'm earing the Net gurus and other god-like creatures talking
  105.   already, I'm just going to explain why I use Pascal.
  106.   For starters, Pascal is a very good language, ideal for the beginner, like 
  107.   BASIC (yech!), but it's powerfull enough to make top-notch programms.
  108.   Also, I'll will be using assembly language in later issues, and Pascal makes
  109.   it so EASY to use. 
  110.   Finally, if you don't like my choice of language, you can stop whining. The
  111.   teory behind each article is very simple, and common with any of the main
  112.   languages (C, C++, Assembly - Yes, that's true... BASIC isn't a decent
  113.   language).
  114.  
  115.     Just one last thing... The final part of the magazine is a little story
  116.   made up by my distorted mind. It's just a little humor I like to write, and
  117.   it hasn't got nothing to do with programming (well, it has a little), but, 
  118.   as I said before, I just like to write it.
  119.  
  120.     1.2. About the author
  121.  
  122.     Ok, so I'm a little egocentric, but tell me... If you had the trouble of 
  123.   writing hundreds of lines, wouldn't you like someone to know you, even by 
  124.   name ?
  125.  
  126.     My name is Diogo de Andrade, alias Spellcaster, and I'm the creator, 
  127.   editor and writer of this magazine. 
  128.     I live in a small town called Setubal, just near Lisbon, the capital of
  129.   Portugal... If you don't know where it is, get an encyclopedia, and look for
  130.   Europe. Then, look for Spain. Next to it, there's Portugal, and Setubal is in
  131.   the middle.
  132.  
  133.     I'm 18 years old, and I just made it in to the university (if you do want
  134.   to know, I'm in the Technical Institute of Lisbon, Portugal), so I'm not 
  135.   a God-Like creature, with dozens of years of practice (I only program by 
  136.   eight years now, and I started in a Spectrum, progressing later to an Amiga.
  137.   I only program in the PC for a year or so), with a mega-computer (I own a 
  138.   386SX, 16 Mhz), that wear glasses with lens that look like the bottom of a 
  139.   bottle (I use glasses, but only sometimes), that has his head bigger than a 
  140.   pumpkin (I have a normal sized head) and with an IQ of over 220 (mine is 
  141.   actually something like 180-190). I can program in C, C++, Pascal, Assembly
  142.   and even BASIC (yech!).
  143.  
  144.     So, if I am a normal person, why do I spend time writing this ?
  145.   Well, because I have the insane urge to write thousands of words every now
  146.   and then, and while I'm at it, I may do something productive, like teaching
  147.   someone. I may be young, but I know a lot about computers (how humble I am;
  148.   I know, modesty isn't one of my qualities).
  149.  
  150.     Just one more thing, if you ever program anything, please send to me... I
  151.   would love to see some work you got, maybe I could learn something with it.
  152.   Also, give me a greet in your program/game/demo... I love seeing my name.
  153.  
  154.     1.3. Distribution
  155.  
  156.     I don't really know when can I do another issue, so, there isn't a fixed
  157.   space of time between two issues. General rule, I will try to do one every two
  158.   weeks, maybe more, probably less (Eheheheh). This is getting to an issue
  159.   every month, so, I'll think I'll change the above text... :)
  160.     'The Mag' is available by the following means:
  161.  
  162.     - Snail Mail : My address is below, in the Contributions seccion... Just
  163.                    send me a disk and tell me what issues you want, and I
  164.                    will send you them...
  165.  
  166.     - E-Mail : If you E-mail me and ask me for some issues, I will Email you
  167.                back with the relevant issues attached.
  168.  
  169.     - BBS's : I don't know for sure what BBS's have or will have my magazine,
  170.               but I will try to post it in the Skyship BBS.
  171.               If you have a BBS and you want to receive 'The Mag', contact me.
  172.  
  173.                  Skyship BBS numbers: (351)+01-3158088
  174.                                       (351)+01-3151435
  175.  
  176.     - Internet : You can access the Spellcaster page and take the issues out
  177.                  of there in:
  178.  
  179.                  http://alfa.ist.utl.pt/~l42686
  180.  
  181.     - Anonymous ftp: I've put this issue of 'The Mag' on the ftp.cdrom.com
  182.                      site... I don't know if they'll accept it there, because
  183.                      that's a demo only site, and my mag doesn't cover only
  184.                      demos, but anyways, try it out... It has lots of source
  185.                      code of demos.
  186.  
  187.     1.4. Contributions
  188.  
  189.     I as I stated before, I'm not a God... I do make mistakes, and I don't 
  190.   have (always) the best way of doing things. So, if you think you've spotted
  191.   an error, or you have thought of a better way of doing things, let me know.
  192.   I'll be happy to receive anything, even if it is just mail saying 'Keep it 
  193.   up'. As all human beings, I need incentive.
  194.  
  195.     Also, if you do like to write, please do... Send in articles, they will be
  196.   welcome, and you will have the chance to see your names up in lights.
  197.     They can be about anything, for a review of a book or program that can
  198.   help a programmer, to a point of view or a moan. I'm specially interested in
  199.   articles explaining XMS, EMS, DMA and Soundblaster/GUS.
  200.  
  201.     If anyone out there has a question or wants to see an article about 
  202.   something in particular, feel free to write... All letters will be answered,
  203.   provided you give me your address.
  204.  
  205.     I'm also trying to start a new demo/game/utility group, and I need all sort 
  206.   of people, from coders (sometimes, one isn't enough), musicians (I can 
  207.   compose, but I'm a bit limited), graphics artists (I can't draw nothing) and
  208.   spreaders... I mean, by a spreader, someone who spreads things, like this mag.
  209.   If you have a BBS and you want it to include this magazine, feel free to
  210.   write me... I don't have a modem, so I can only send you 'The Mag' by Email.
  211.  
  212.     You can also contact me personally, if you study on the IST (if you don't
  213.   know what the IST is, you don't study there). I'm the freshman with the
  214.   black hair and dark-brown eyes... Yes, the one that is trying to make people
  215.   believe he can code !! :)
  216.  
  217.     My adress is:
  218.                  Praceta Carlos Manito Torres, nº4/6ºC
  219.                  2900 Setúbal
  220.                  Portugal
  221.  
  222.     Email: dgan@rnl.ist.utl
  223.            l42686@alfa.ist.utl.pt
  224.  
  225.     And if you want to contact me on the lighter side, get into the Lost Eden
  226.   talker... To do that telnet to:
  227.  
  228.                         Alfa.Ist.Utl.Pt  : Port 1414
  229.  
  230.     If that server is down, try the Cital talker, in
  231.  
  232.                         Zeus.Ci.Ua.PT    : Port 6969
  233.  
  234.     I'm almost always there in the afternoon... As you may have guessed already,
  235.   my handle is Spellcaster (I wonder why...)...
  236.  
  237.     1.5. Hellos and greets
  238.  
  239.     I'll say hellos and thanks to all my friend, especially for those who put 
  240.   up with my constant whining.
  241.     Special greets go to Denthor from Asphyxia (for the excelent VGA trainers),
  242.   Draeden from VLA (for assembly tutorials), Joaquim Elder Guerreiro, alias
  243.   Dr.Shadow (Delta Team is still up), Joao Neves for sugestions, testing and
  244.   BBS services, and all the demo groups out there.
  245.     I will also send greets to everybody that responded to my mag... Thank
  246.   you very much !
  247.     Super Very Special thanks go to: Ricardo 'Scorpio' Oliveira...
  248.  
  249. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  250.  
  251.   2. Mailroom
  252.  
  253.     Well, I've got another letter telling me I SUCK ! Just kidding... I got
  254.   a letter of someone who noticed one error in a previous issue. It was a
  255.   friend of mine called Nuno, and he studies in the same school as I do, and
  256.   he is also trying to major in Computer Engeneering (hope he doesn't end like
  257.   me and he makes through !)...
  258.     Well, so what's the screw-up, you may ask... And I will answear... In issue
  259.   four, in the graphics section, in the part about circles, I told you that
  260.   Pascal uses reverse-angling, that is, that the trigonometrical circle goes
  261.   in a clockwise direction... Well, this is WRONG !! Pascal goes in the
  262.   standart (anti-clockwise) direction... The reason that made me believe so
  263.   was that in real life, usually the y axis increases the more you go upwards
  264.   and decreases going downwards... But in the computer sense, this goes
  265.   reverse, and that is why I screwed up... Sorry but that ! :)
  266.     Thanks, NSJ !
  267.  
  268.   -----------------------------------------------------------------------------
  269.  
  270.     Other letter I got was from a guy who told me that he got an Heap Overflow
  271.   error, when he runned the same program lot's of times... I've checked the
  272.   program and realized that it was my fault ! I forget to told you, when I
  273.   talked about virtual screens, back in issue 5, that you should de-allocate
  274.   the pointers to the virtual pages, because they are filling the memory.
  275.   So, in the end of the program, when you don't need the virtual screens anymore
  276.   you should call the CloseVirt procedure:
  277.  
  278.                       Procedure CloseVirt;
  279.                       Var A:Byte;
  280.                       Begin
  281.                            For A:=1 To Npages Do
  282.                            Begin
  283.                                 Freemem(Virt[A],64000);
  284.                                 VP[A]:=$A000;
  285.                            End;
  286.                       End;
  287.  
  288.     Sorry about that... :)
  289.  
  290. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  291.  
  292.   3. Coding sites
  293.  
  294.     Ok, this is the article writen by Scorpio (as you will guess)... I,
  295.   Spellcaster will make my coments between square brackets []...
  296.  
  297.     I am Ricardo Manuel Oliveira, aka Scorpio and I live in Portugal...
  298.     [ I already told you that !! :) ]
  299.     I have read all the issues of The Mag (like all of you :)) and I was
  300.   very angry 'cos Spellcaster didn't know the URL of my page (Check 'THE
  301.   MAG #7).. :)...
  302.     He didn't know Denthor's one too, though... :)
  303.     [ So, I'm no URL storing machine !! :) ]
  304.     Now, more seriously:
  305.     This article is a coding-resources list gathered by me... Why have I decided
  306.   to share it with you all? 'Cos I'm happy right now... I have created a
  307.   HTML page about my local soccer club (Vitoria Sport Clube, for portuguese
  308.   people), and it appeared reviewed in a national magazine (CyberNet, for ...)
  309.     So, I have felt that I have to share this joy with lots of people and
  310.   I'm contributing to the growth of 'THE MAG'... Since I read it, I could see
  311.   my name there, right ?
  312.     [ Of course you can !! Write some more !! I like having less work to do ! ]
  313.  
  314.   DEMO-RELATED CODING PAGES:
  315.   --------------------------
  316.  
  317.   http://www.dur.ac.uk/~d405ua/demoftps.html
  318.   Extensive list of demo-related FTP servers (UK)
  319.  
  320.   http://www.cdrom.com/pub/demos/hornet/8086
  321.   8086 Compo + Coding examples to the 8086
  322.  
  323.   http://196.6.101.37:80/grants/Asphyxya/Asphyxya.html
  324.   Denthor / Asphyxia 's Homepage GREAT vga-coding Tutorials!!!
  325.  
  326.   http://alfa.ist.utl.pt/~l42686/
  327.   Spellcaster's Homepage - 'THE MAG' (general (demo/vga)coding magazine)
  328.   You're reading it
  329.   [ My great page ! He forgot that 'The Mag' also haves stuff about game
  330.     making and the Adventures of Spellcaster !! :) ]
  331.  
  332.   GENERAL-CODING PAGES:
  333.   ---------------------
  334.  
  335.   http://www.cs.vu.nl/~jprins/tp.html
  336.   Turbo Pascal Programmer's page
  337.   If you're into Pascal, CHECK THIS ONE NOW!!!
  338.  
  339.   http://www.interlog.com/~jfanjoy/swag/swag.html
  340.   SWAG Homepage - Pascal code for everybody (_LOTS_ OF CODE)
  341.  
  342.   http://www.fys.ruu.nl/~faber/amain.html
  343.   Faber's Hotlist Assembly links
  344.  
  345.   http://www.cera2.com/assembly
  346.   Assembly Language HotLists and Major Resources
  347.  
  348.   http://www.caiw.nl/~jdbruijn/cl.html
  349.   Code Language Page, by Jack de Bruijn
  350.  
  351.   http://onyx.idbsu.edu/~jcofflan/
  352.   Joe's Assembly Language Page, by Joe :-)
  353.  
  354.   http://www.netrunner.net/~irvinek/asm.htm
  355.   Assembly Language Sources, by Kip P. Irvine
  356.  
  357.   Where can I find CODE?:
  358.   -----------------------
  359.  
  360.   ftp://ftp.cdrom.com/pub/demos/code
  361.   Democoding examples and more... a LOT more
  362.   It's in USA, a bit _SLOW_ for european users during the afternoon...
  363.  
  364.   ftp://ftp.luth.se/pub/msdos/demos
  365.   Mirror of cdrom
  366.   _FAST_ for european users (_VERY_FAST_ indeed :)) (includes FTPMAIL!!!)
  367.  
  368.   ftp://ftp.co.iup.edu/code
  369.   Mirrors cdrom's CODE dir.
  370.   'Bit slow...
  371.  
  372.   ftp://x2ftp.oulu.fi/pub/msdos/programming
  373.   This place is huge! It'll keep you busy for a LONG time.
  374.  
  375.   ftp://garbo.uwasa.fi/pub/
  376.   Another BIG place... Happy searchin'
  377.  
  378.   Oh, yes... Check the alt.lang.* newsgroups
  379.   [ And the following groups:
  380.     comp.graphics.algorithms
  381.     rec.games.programmer
  382.     comp.programming
  383.     alt.sys.ibm.pc.demos (I think this is it... Search for demos... :) ]
  384.  
  385.   At last, if you want more links try my bookmarks at
  386.   http://wwwalu.ci.uminho.pt:8888/~si17899/bookmark.html
  387.   To contact me, email me at: si17899@ci.uminho.pt
  388.   [ Check it out !! :) ]
  389.  
  390.     Spellcaster, take the lead...
  391.  
  392.     Thanks Scorpio ! Feel free to write some more ! :)
  393.   So, let's move on to the next article...
  394.  
  395. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  396.  
  397.   4. Designing a text adventure - Part I
  398.  
  399.     This article is intended for the beginners who want to do games. I know
  400.   that text adventures are definetly out, but the ideas behind a text adventure
  401.   are very similar to those found in graphic adventures, so what I say here
  402.   can be expanded to a graphic adventure...
  403.     Note that these are my personal views on how a text adventure should be
  404.   coded and designed... These articles will teach _EVERY_ step in the creation
  405.   of a text adventure, from designing and plotline creation, to programming, to
  406.   pointers on how to further expand the system...
  407.     There can be some errors and irregularities in the code and explanations,
  408.   because I'm writing this at the same time I'm coding the adventure, so I
  409.   will sometimes make mistakes... If you spot one, or have any doubts, mail me !
  410.  
  411.     4.1. Plot creation
  412.  
  413.     This part of the article will give you some pointers on how you should start
  414.   to build your text adventure...
  415.     So, for me, one the more important parts of _ANY_ game is the plot... It's
  416.   the first thing I do, because I believe that the other pieces of the game
  417.   (playability and such) will come together, if you have a good story. In this
  418.   stage you must try to be original... Because it's getting harder and harder
  419.   to be original in the plot, you must be original in other things... For
  420.   example, I do most of the story of the game with the idea of SUSPENSE ! I
  421.   like to put the hero in the game with no idea of what he is supposed to
  422.   accomplish... This is my idea... Other piece of originality is the atenction
  423.   to detail... This is also very important, for it adds very much for the
  424.   atmosphere of the game... So, if you follow these ideas, you can make a text
  425.   adventure that is fun to play, even in these DOOM-clones filled times...
  426.     Just for the record, I will state something about Doom... Cool graphics and
  427.   gameplay, crappy story !! I admire the guys at ID software (technically
  428.   speaking), but I would like to shoot their desing department ! :)
  429.     Another important of the detail is to pay heed to the time/space in which
  430.   the game occurs... If you are doing an adventure passed into outer-space, you
  431.   shouldn't put an old Chevy in it... :)
  432.     So, for our text adventure, I will conceive a little stupid story... So, let
  433.   me think... Hum... This is hard... :)
  434.     Ok, I got it! Let's imagine that the hero's uncle has just passed out (on
  435.   the 25 April 1996... This is details, that make up the atmosphere), and he
  436.   had sent you a letter (the letter is dated of the 23 April 1996... Again,
  437.   detail) before he did so, saying that he has a treasure hidden in his
  438.   mansion (that is in a high cliff, near the ocean), and if you can found it,
  439.   it is yours... So, filled with lust for gold, the hero sets foot for the
  440.   mansion. Crappy story, I know, but this one enables me to explain how to
  441.   make a basic text adventure...
  442.     Another thing I think it's very important in a game (of any kind) is the
  443.   title... I don't know, but I spend a lot of time thinking of the name for a
  444.   game... The name should give the user the will to explore the game further...
  445.     So, one possible title for this game should could be 'The Mansion', but
  446.   this doesn't call the atencion... So, you could name it 'Treasure Mansion',
  447.   but this title is crappy, because the word 'treasure' has been used so many
  448.   times in games and titles that has became vulgar... Other examples of words
  449.   like that is 'Prince', 'Princess', 'Dragon'. Let's try another time... How
  450.   about 'Evil Mansion'. It's getting better, but I think it isn't suitable for
  451.   the game yet... We also have variations on the theme: 'Evil Home', 'Home of
  452.   Evil', 'Evil Lair'... But still, altough they are cool, they remember a game
  453.   where there is a house possessed by an evil sorcerer... And this is not the
  454.   case (altough it could be)... The only problem (in this story I'm developing)
  455.   in the house is that it has a couple of monsters/haunts... We could call it
  456.   'Haunted House', or 'Haunted Mansion', but 'Haunted' is one of those words,
  457.   similar to 'treasure'... So, we can be a bit more inventive, and add to the
  458.   atmosphere. We could say that the name of the mansion is 'Fanglore', and call
  459.   the game just that: 'Fanglore'... using this name, we've added to the
  460.   atmosphere (because we added the detail of the name of the house), and we
  461.   gave a name to the game that make the user not know what is he going to
  462.   see... :) So, the process of creating the great text-adventure 'Fanglore' is
  463.   underway... :)
  464.  
  465.     4.2. Plotline
  466.  
  467.     Next in the list (for me) is the plotline and map creation. These two steps
  468.   should be made simultaneosly...
  469.     The plotline is the course the game should follow normally...
  470.     In Fanglore, the plotline is:
  471.  
  472.          Going to Fanglore -> Finding the treasure -> Escape the house
  473.  
  474.     A game can have several endings, and different soluttions for the game, and
  475.   that increases the complexity of the plotline (and the overall interest of
  476.   the game)... But the way of doing this is the same.
  477.     Each part of the plotline is a different step of the game. Now, every
  478.   step of the game has different objectives (though the game has only one
  479.   objective). For example, the first step 'Going to Fanglore' has his own
  480.   objective, that is, to enter the mansion. Also, every step of the game has
  481.   a reason of existing... The basic reason is the completion of the game, but
  482.   you must explain, that is, you must know what put the character(s) in that
  483.   particular position. The first step of Fanglore exists because the taxi left
  484.   us at the door of the mansion, that is closed for years, and you don't have
  485.   the key. Also, very step of the game have a way to completing it's objective,
  486.   and that also needs to be defined. Again, in the first step, the way of
  487.   getting into Fanglore is to find a shovel and knock down the door... You
  488.   also have to take in account possible problems and a way to overcome them...
  489.   The problems in a text adventure are not only made of a difficult puzzle to
  490.   resolve; monsters and other similar things also have it's effects... In the
  491.   first part there aren't any problems, but in the second part, there is a
  492.   room that is filled with gas, and you have to use a gas mask to go past that
  493.   room, and to find the mask, you must go to the kitchen of the house and open
  494.   the oven... That is were the mask is...
  495.   So, scematically:
  496.  
  497.              - Going to Fanglore
  498.                Objective ?
  499.                  To get into Fanglore.
  500.                Why ?
  501.                  Because the cab left us at the door and we don't have the key.
  502.                How ?
  503.                   Get the shovel
  504.                   Knock down door with it (the door opens)
  505.  
  506.     The other steps of the plotline:
  507.  
  508.              - Finding the treasure
  509.                Objective ?
  510.                  Find the treasure.
  511.                Why ?
  512.                  Because that is the point of the game.
  513.                How ?
  514.                  Go to kitchen
  515.                  Open oven
  516.                  Get gas mask
  517.                  Wear mask
  518.                  Go past the gas room
  519.                  Find the library
  520.                  Push bookshelf (you found a secret passage)
  521.                  Go through passage
  522.                  You found the vault with the treasure
  523.                Other problems ?
  524.                  Monsters in some rooms, that can kill you. You can kill them,
  525.                  if you have the sword (that is in the main room)...
  526.  
  527.              - Escape the house
  528.                Objective ?
  529.                  Get out of Fanglore.
  530.                Why ?
  531.                  Because the passage has closed when you passed through it, and
  532.                  you are stuck...
  533.                How ?
  534.                  Push a brick in the wall (reveals another secret passage)
  535.                  Go through passage
  536.  
  537.     So, the plotline is complete... You should also create a map while you are
  538.   doing the plotline...
  539.  
  540.     4.3. Map creation
  541.  
  542.     As said, the map should be made at the some time as the plotline. There
  543.   isn't a standart way of doing the map... The ideia is this: In the map, you
  544.   should setup were are going to be the exits of a room (the relantion between
  545.   the various rooms) and you should also number all the rooms.
  546.     The first draft for a map is shown in picture Map01.Pcx. It has six rooms:
  547.  
  548.     1. Kitchen                 2. Main Hall                  3. Gate
  549.     4. Gas Room                5. Library                    6. Treasure Room
  550.  
  551.     For the plotline, you already know the importance of each of these rooms.
  552.     The yellow line connecting rooms mean that there is an exit from one to
  553.   another. If there isn't a line, there isn't an exit. The orange dotted line
  554.   means a conditional exit, that is, an exit that is only open at certain times,
  555.   or when you have made something (for example, the exit from room 3 to room 2
  556.   only opens when you break down the door). An arrow on the end of a exitline
  557.   means an unidirectional passage... For example, you can go east from room 5
  558.   to room 6, but you can't go west back to room 5.
  559.  
  560.     But, this doesn't give much to explore, and almost all players like to
  561.   search dozens of rooms... It is part of the detail... For example, in a
  562.   mansion should have a dinning room, and a great garden... Well, these aren't
  563.   present in the draft. And a mansion should also have bedrooms, and Fanglore
  564.   as we designed doesn't have them.
  565.     So, you make a more detailed map... This is in Map02.Pcx. It has 22 rooms.
  566.   The rooms that are in green are the garden-rooms, and the others are the
  567.   mansion-rooms. We've also added the dinning room also. But we didn't added
  568.   the bedroom. Well, if you want, you can ommit certain details, but you have
  569.   to add others. In the case of bedrooms, you can say that there is a stair in
  570.   the Main Hall, that takes you to the upper floor, but the stair is blocked,
  571.   so you can't go that way...
  572.     So, the map is now complete.
  573.  
  574.     4.4. Getting started
  575.  
  576.     So, let's get started in the coding department... We first should get the
  577.   room data. I've made a little program that enables you to type in the room
  578.   data (with lame source code). Each room is a record that has the exits info,
  579.   and the description of the room. So:
  580.  
  581.              Type RoomType=Record
  582.                                  Desc:Array[1..10] of String[79];
  583.                                  North,South,East,West:Byte;
  584.                            End;
  585.  
  586.     The description of the room is an array of strings, with only 79 chars per
  587.   string because the screen only has enough space for 80 lines, and you must
  588.   take in acount the return character. You don't need to use the complete 79
  589.   columns, neither the 10 lines of text. You just have to type in a line with
  590.   a single '*' after the last line of text. If you want to use the 10 lines,
  591.   the '*' is left out.
  592.     As you have various rooms, you should have an array with the various rooms:
  593.  
  594.               Const NumberRooms=22;
  595.  
  596.               Var Rooms:Array[1..NumberRooms] of RoomType;
  597.  
  598.     The fields North, South, East and West are a number that indicates to
  599.   what room you should go  if you go in that direction. A zero there indicates
  600.   that there isn't an exit in that direction. For example, if Rooms[1].North=2
  601.   then, if you go north in room 1 you will go to room 2.
  602.     Fanglore will use a file called Room.Dat to store the room data.
  603.     So, to end this issue's article in text adventure, here is the procedure
  604.   to read the room data:
  605.  
  606.               Procedure ReadRoomData;
  607.               Var F:Text;
  608.                   A,B:Byte;
  609.                   Flag:Boolean;
  610.               Begin
  611.                    { Prepares the text file for accessing }
  612.                    Assign(F,'Room.Dat');
  613.                    Reset(F);
  614.                    { For every room in the game }
  615.                    For A:=1 To NumberRooms Do
  616.                    Begin
  617.                         { Clear the room's description }
  618.                         For B:=1 To 10 Do Rooms[A].Desc[B]:='';
  619.                         { Read the description of the room }
  620.                         Flag:=True;
  621.                         B:=1;
  622.                         While Flag Do
  623.                         Begin
  624.                              Readln(F,Rooms[A].Desc[B]);
  625.                              If (B=10) Or (Rooms[A].Desc[B]='*') Then
  626.                                 Flag:=False;
  627.                              Inc(B);
  628.                         End;
  629.                         { Read exit data }
  630.                         Readln(F,Rooms[A].North);
  631.                         Readln(F,Rooms[A].South);
  632.                         Readln(F,Rooms[A].East);
  633.                         Readln(F,Rooms[A].West);
  634.                    End;
  635.                    Close(F);
  636.               End;
  637.  
  638.     The procedure is self-explainatory, with the exceptions of a few points.
  639.     If you are wondering why do we clear the rooms description before we load,
  640.   if there isn't anything there, this is the answear: Pascal, when it creates
  641.   a variable, puts it anywhere in memory it can fit, but it can be something
  642.   there, and Pascal doesn't erase it... It is good programming pratice to clear
  643.   the comtent of a variable before using it (jee, I sound like one of my
  644.   teachers). Second of all, I don't know if I already showed you what does the
  645.   Inc keyword. The Inc keyword increases the variable given by one (if no other
  646.   parameter is specified). So, Inc(B) is equal to B:=B+1, and Inc(B,2) is equal
  647.   to B:=B+2...
  648.  
  649.     Well, the call to this procedure should be made in a procedure called
  650.   something like Init, which sets up all variables and prepares the game to
  651.   be played. So, procedure Init is (for the moment, for there are other stuff
  652.   to initialize) like this:
  653.  
  654.               Procedure Init;
  655.               Begin
  656.                    ReadRoomData;
  657.               End;
  658.  
  659.     And the Init procedure should be called from the main program. So, the
  660.   main program should be like this, for the meanwhile:
  661.  
  662.               Begin
  663.                    Init;
  664.               End.
  665.  
  666.     This all is already typed in file FangLore.Pas...
  667.     NOTE: Any file generated with the RoomGen program can be altered by hand,
  668.           that is, you can load it to any ASCII editor and edit any errors
  669.           and alterations you want to make... Don't forget to save as ASCII
  670.           the altered file !
  671.     So, in next issue, I will tell you how to build the phrase parser and some
  672.   of the basic verbs... Until then, try to do it by yourself... :)
  673.  
  674. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  675.  
  676.   5. Our friend, the pointer - Part III
  677.  
  678.     Well, this is the last of the articles on pointers... Nobody liked them, so
  679.   I won't waste my time with them anymore... :(
  680.     In this part I will discuss dynamic structures to the highest degree (I'm
  681.   such a liar !! :) ).
  682.     So, let's assume you want to do a database that stores the names and
  683.   phonenumbers of all your friends (if you are like me, you have _LOTS_ of
  684.   friends... :))) ). You could do it in the tradicional manner:
  685.  
  686.                   Type FriendRec=Record
  687.                                        Name:String;
  688.                                        Phone:String;
  689.                                  End;
  690.  
  691.                   Var Friends:Array[1..100] Of FriendRec;
  692.  
  693.     But this would impose a limit of 100 friends, and you would spend your
  694.   precious variable memory... Even if you increased the size of the array,
  695.   you would have a limit of 128 friends, because you have 2 strings, that
  696.   ocuppy 256 bytes each, and: 2*256*128=65536, that is the maximum memory you
  697.   can allocate for variables... That is no good... You should be able to add
  698.   phonenumbers 'till you run out of memory...
  699.     You could use the method teached in number one, using static pointers, but
  700.   that only enables to use 65536 bytes of memory, and that would only solve
  701.   the problem of lack of variable memory.
  702.     You can use a variant of method 2, that it is what I'm going to teach you.
  703.  
  704.     First, define this:
  705.  
  706.                        Type PFriend=^FriendRec;
  707.                             FriendRec=Record
  708.                                             Name:String;
  709.                                             Phone:String;
  710.                                             Next:PFriend;
  711.                                       End;
  712.  
  713.                        Var Friends:PFriend;
  714.  
  715.     Ok, you did understand it, did you ?
  716.     Think about this... What we are doing is to create a structure that points
  717.   to a place in memory where a structure of type FriendRec is allocated. In
  718.   the FriendRec structure it is defined another pointer that points to another
  719.   structure of type FriendRec, and so forth... Look at the scheme below... In
  720.   the beggining, variable Friends points to a random position in memory:
  721.  
  722.       Friends --> ?
  723.  
  724.     Then, you allocate the structure associated with variable Friends... To do
  725.   so, you use the New command... So, you do:
  726.  
  727.                               New(Friends);
  728.  
  729.     The structure will change and become something like this:
  730.  
  731.       Friends --> Name
  732.                   Phone
  733.                   Next --> ?
  734.  
  735.     To access now the name and phonenumber of the first friend, you just do:
  736.  
  737.                               Friends^.Name:='Diogo Andrade';
  738.                               Friends^.Phone:='555-1355';
  739.                               Writeln(Friends^.Name);
  740.  
  741.     You should make always:   Friends^.Next:=NIL;  I will explain the reason
  742.   why later.
  743.     And if you want to create another structure, that is, another friend ?
  744.   Yes, you do:
  745.                               New(Friends^.Next);
  746.  
  747.     The structure would look something like this:
  748.  
  749.       Friends --> Name    --> Name
  750.                   Phone   |   Phone
  751.                   Next ---|   Next --> ?
  752.  
  753.     So, the fields would be accessed by:
  754.  
  755.                             Friends^.Next^.Name
  756.                             Friends^.Next^.Phone
  757.                             Friends^.Next^.Next
  758.  
  759.     But, if you increase the number of structures, it would become impossible
  760.   to access them all... So, you use a little trick: you assign an extra variable
  761.   to the first record, and then you go through all of them, like this:
  762.  
  763.                Procedure GoLast;
  764.                Var Tmp:PFriends;
  765.                Begin
  766.                     Tmp:=Friends;
  767.                     While Tmp^.Next<>NIL Do
  768.                     Begin
  769.                          Tmp:=Tmp^.Next;
  770.                     End;
  771.                     .....
  772.                     { Tmp now points to the last structure }
  773.                     .....
  774.                End;
  775.  
  776.     Now do you understand what does the NIL value is needed for ? To know what
  777.   is the last... :))
  778.     I know this sounds complicated at first, but with pratice it will come to
  779.   you as natural as 2+2=5... :)
  780.     Just a few notes...
  781.     1) Never loose the pointer to the first position in memory, or else you
  782.        can't access that address... As the matter of fact, you shouldn't loose
  783.        _ANY_ pointer, or else they will become lost pieces of memory you can
  784.        no longer access...
  785.     2) Don't forget to deallocate the pointers when you end the program, or
  786.        else you will loose the memory on which they are allocated... They don't
  787.        just go away like variables in a Pascal program... They need to be
  788.        deallocated with the Dispose keyword...
  789.  
  790.     Well, I think this wraps it up... As I said earlier, this is the last of the
  791.   pointer articles, so I'm going to start a new series in next issue... I don't
  792.   know what it will be, but I think I'm going to make it about assembly...
  793.   Stay tuned... Spellcaster out... :)
  794.  
  795. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  796.  
  797.   6. How too make a cool starfield
  798.  
  799.     This article is about creating a starfield... Remember the starfield
  800.   program I gave in the Graphics article, last issue ? Well, that program
  801.   SUCKED big time ! :) As I don't like beeing regarded as a bad programmer
  802.   (altough I am :) ), here is an article on about how to create a
  803.   starfield... Well, starfields are funny... They are beutifull and exciting...
  804.   And this text is sucking ! :)
  805.     Now, really, the problem of the starfield in issue 7 is that it spent too
  806.   much of the processor (it wasn't efficient, because it moved the entire
  807.   screen, when it only needed to move a few pixels) and it was unreallistic,
  808.   because we all know that stars that are further away from us move slower that
  809.   stars close to us...
  810.     So, let's get down to business... One of the reasons why the starfield of
  811.   last issue's was so slow was that you scrolled _ALL_ the pixels of the screen,
  812.   that is, you did 64000 moves !! That's ridiculous, if you think that the
  813.   screen only had 1000 stars, that is, you could move all the stars using only
  814.   1000 memory moves... That is 64 times faster !
  815.     So, the ideia is this... You keep track of the coordinates of all the stars,
  816.   and you move them wherever you want...
  817.     Ok, so one star is a record:
  818.  
  819.                Type Star=Record
  820.                                X,Y:Integer;
  821.                                Color:Byte;
  822.                          End;
  823.  
  824.     And lots of stars are an array:
  825.  
  826.                Var Stars:Array[1..1000] Of Star;
  827.  
  828.     Then, you must initialize the stars, the graphics and the palette... We
  829.   will use the Mode13h unit, that was given the last issue:
  830.  
  831.                Procedure Init;
  832.                Var A:Word;
  833.                Begin
  834.                     InitGraph;
  835.                     { Sets up 16 grays... }
  836.                     For A:=0 To 15 Do SetColor(A,A*4,A*4,A*4);
  837.                     { Sets up stars }
  838.                     For A:=1 To 1000 Do
  839.                     Begin
  840.                          Stars[A].X:=Random(320);
  841.                          Stars[A].Y:=Random(200);
  842.                          Stars[A].Color:=Random(15)+1;
  843.                     End;
  844.                End;
  845.  
  846.     Note: If you are wondering why Stars[A].Color:=Random(15)+1, know this:
  847.           0 <= Random(x) < x ; but, in this example:
  848.           0 <= Random(15) < 15 ; but a star shouldn't get color 0, so we add
  849.           one to Random(15) and we get:
  850.           1 <= Random(15)+1 < 16... So we get the colors we want... :)
  851.  
  852.     Having done this, let's move on to more theory... The ideia is this:
  853.  
  854.                       1) Clear Stars
  855.                       2) Move Stars
  856.                       3) Draw Stars
  857.                       4) Go back to step 1
  858.  
  859.     So, how do you do this, you may ask... Well, like this...
  860.  
  861.     Step 1: You just draw the stars in their positions, but in color 0 (or
  862.             whatever is the color of your background). Remember to only clear
  863.             the stars before you move them, or else you don't clear them,
  864.             you'll just draw them in color 0 elsewhere !
  865.  
  866.             Procedure ClearStars;
  867.             Var A:Word;
  868.             Begin
  869.                  For A:=1 To 1000 Do PutPixel(Stars[A].X,Stars[A].Y,0,VGA);
  870.             End;
  871.  
  872.     Step 2: You should give the ability to move the stars to every direction
  873.             you may want... As this is a bidimensional starfield, you have
  874.             2 incrementation variables. The ideia is to sum to the coordinates
  875.             of the stars a value given to the procedure.
  876.  
  877.             Procedure MoveStars(Ix,Iy:Integer);
  878.             Var A:Integer;
  879.             Begin
  880.                  For A:=1 To 1000 Do
  881.                  Begin
  882.                       Stars[A].X:=Stars[A].X+Ix;
  883.                       Stars[A].Y:=Stars[A].Y+Iy;
  884.                  End;
  885.             End;
  886.  
  887.             Now, let's assume you want to move the stars left... You just
  888.             do MoveStars(-1,0); Easy, isn't it ?
  889.             Wrong ! If you do like this, you can get an error... For example,
  890.             let's assume:
  891.                          Stars[1].X:=0;
  892.                          Ix:=-1;
  893.             If you execute the MoveStars procedure, you will get an error,
  894.             because Stars[1].X is a variable of type Word, that doesn't allow
  895.             negative numbers!
  896.             The best way to fix this is to make the X and Y fields of the
  897.             Star's record variables of type Integer and check if their are out
  898.             of bounds... If they are, you wrap it around the screen.
  899.             Wrap around the screen is a process that means that is a star has
  900.             coordinates (0,10) and it is scrolled left, a new star will appear
  901.             at (319,10)... So, the new procedure is like this:
  902.  
  903.             Procedure MoveStars(Ix,Iy:Integer);
  904.             Var A:Integer;
  905.             Begin
  906.                  For A:=1 To 1000 Do
  907.                  Begin
  908.                       Stars[A].X:=Stars[A].X+Ix;
  909.                       Stars[A].Y:=Stars[A].Y+Iy;
  910.                       If Stars[A].X<0 Then Stars[A].X:=319;
  911.                       If Stars[A].X>319 Then Stars[A].X:=0;
  912.                       If Stars[A].Y<0 Then Stars[A].Y:=199;
  913.                       If Stars[A].Y>199 Then Stars[A].Y:=0;
  914.                  End;
  915.             End;
  916.  
  917.     Step 3: Well this should be simple enough... You just draw the stars ! :)
  918.  
  919.             Procedure DrawStars;
  920.             Var A:Word;
  921.             Begin
  922.                  For A:=1 To 1000 Do
  923.                    PutPixel(Stars[A].X,Stars[A].Y,Stars[A].Color,VGA);
  924.             End;
  925.  
  926.     Well, this is easy enough, right ? The whole program is here:
  927.  
  928.                Program Starfield;
  929.  
  930.                Uses Mode13h;
  931.  
  932.                Type Star=Record
  933.                                X,Y:Integer;
  934.                                Color:Byte;
  935.                          End;
  936.  
  937.                Var Stars:Array[1..1000] Of Star;
  938.                    A:Integer;
  939.  
  940.                Procedure Init;
  941.                Var A:Word;
  942.                Begin
  943.                     InitGraph;
  944.                     { Sets up 16 grays... }
  945.                     For A:=0 To 15 Do SetColor(A,A*4,A*4,A*4);
  946.                     { Sets up stars }
  947.                     For A:=1 To 1000 Do
  948.                     Begin
  949.                          Stars[A].X:=Random(320);
  950.                          Stars[A].Y:=Random(200);
  951.                          Stars[A].Color:=Random(15)+1;
  952.                     End;
  953.                End;
  954.  
  955.                Procedure ClearStars;
  956.                Var A:Word;
  957.                Begin
  958.                     For A:=1 To 1000 Do PutPixel(Stars[A].X,Stars[A].Y,0,VGA);
  959.                End;
  960.  
  961.                Procedure MoveStars(Ix,Iy:Integer);
  962.                Var A:Integer;
  963.                Begin
  964.                     For A:=1 To 1000 Do
  965.                     Begin
  966.                          Stars[A].X:=Stars[A].X+Ix;
  967.                          Stars[A].Y:=Stars[A].Y+Iy;
  968.                          If Stars[A].X<0 Then Stars[A].X:=319;
  969.                          If Stars[A].X>319 Then Stars[A].X:=0;
  970.                          If Stars[A].Y<0 Then Stars[A].Y:=199;
  971.                          If Stars[A].Y>199 Then Stars[A].Y:=0;
  972.                     End;
  973.                End;
  974.  
  975.                Procedure DrawStars;
  976.                Var A:Word;
  977.                Begin
  978.                     For A:=1 To 1000 Do
  979.                        PutPixel(Stars[A].X,Stars[A].Y,Stars[A].Color,VGA);
  980.                End;
  981.  
  982.                Procedure MoveAround(Ix,Iy:Integer);
  983.                Begin
  984.                     ClearStars;
  985.                     MoveStars(Ix,Iy);
  986.                     DrawStars;
  987.                End;
  988.  
  989.                Begin
  990.                     Init;
  991.                     For A:=1 To 100 Do MoveAround(-1,0);
  992.                     For A:=1 To 100 Do MoveAround(-1,1);
  993.                     For A:=1 To 100 Do MoveAround(0,1);
  994.                     For A:=1 To 100 Do MoveAround(1,1);
  995.                     For A:=1 To 100 Do MoveAround(1,0);
  996.                     For A:=1 To 100 Do MoveAround(1,-1);
  997.                     For A:=1 To 100 Do MoveAround(0,-1);
  998.                     For A:=1 To 100 Do MoveAround(-1,-1);
  999.                     Closegraph;
  1000.                End.
  1001.  
  1002.     So, if you run this, you realize that this FLICKER A LOT !! And that
  1003.   anoying ! Ok, to mend this, you should use virtual screens... The ideia is
  1004.   the same, differing only that you clear and draw the stars in the virtual
  1005.   screen and then you copy the virtual screen to the VGA screen... That will
  1006.   avoid the flicker... Program:
  1007.  
  1008.                Program VirtualStarfield;
  1009.  
  1010.                Uses Mode13h;
  1011.  
  1012.                Type Star=Record
  1013.                                X,Y:Integer;
  1014.                                Color:Byte;
  1015.                          End;
  1016.  
  1017.                Var Stars:Array[1..1000] Of Star;
  1018.                    A:Integer;
  1019.  
  1020.                Procedure Init;
  1021.                Var A:Word;
  1022.                Begin
  1023.                     InitGraph;
  1024.                     InitVirt;
  1025.                     Cls(0,VP[1]);
  1026.                     { Sets up 16 grays... }
  1027.                     For A:=0 To 15 Do SetColor(A,A*4,A*4,A*4);
  1028.                     { Sets up stars }
  1029.                     For A:=1 To 1000 Do
  1030.                     Begin
  1031.                          Stars[A].X:=Random(320);
  1032.                          Stars[A].Y:=Random(200);
  1033.                          Stars[A].Color:=Random(15)+1;
  1034.                     End;
  1035.                End;
  1036.  
  1037.                Procedure ClearStars;
  1038.                Var A:Word;
  1039.                Begin
  1040.                     For A:=1 To 1000 Do PutPixel(Stars[A].X,Stars[A].Y,0,VP[1]);
  1041.                End;
  1042.  
  1043.                Procedure MoveStars(Ix,Iy:Integer);
  1044.                Var A:Integer;
  1045.                Begin
  1046.                     For A:=1 To 1000 Do
  1047.                     Begin
  1048.                          Stars[A].X:=Stars[A].X+Ix;
  1049.                          Stars[A].Y:=Stars[A].Y+Iy;
  1050.                          If Stars[A].X<0 Then Stars[A].X:=319;
  1051.                          If Stars[A].X>319 Then Stars[A].X:=0;
  1052.                          If Stars[A].Y<0 Then Stars[A].Y:=199;
  1053.                          If Stars[A].Y>199 Then Stars[A].Y:=0;
  1054.                     End;
  1055.                End;
  1056.  
  1057.                Procedure DrawStars;
  1058.                Var A:Word;
  1059.                Begin
  1060.                     For A:=1 To 1000 Do
  1061.                        PutPixel(Stars[A].X,Stars[A].Y,Stars[A].Color,VP[1]);
  1062.                End;
  1063.  
  1064.                Procedure MoveAround(Ix,Iy:Integer);
  1065.                Begin
  1066.                     ClearStars;
  1067.                     MoveStars(Ix,Iy);
  1068.                     DrawStars;
  1069.                     WaitVbl;
  1070.                     CopyPage(VP[1],VGA);
  1071.                End;
  1072.  
  1073.                Begin
  1074.                     Init;
  1075.                     For A:=1 To 100 Do MoveAround(-1,0);
  1076.                     For A:=1 To 100 Do MoveAround(-1,1);
  1077.                     For A:=1 To 100 Do MoveAround(0,1);
  1078.                     For A:=1 To 100 Do MoveAround(1,1);
  1079.                     For A:=1 To 100 Do MoveAround(1,0);
  1080.                     For A:=1 To 100 Do MoveAround(1,-1);
  1081.                     For A:=1 To 100 Do MoveAround(0,-1);
  1082.                     For A:=1 To 100 Do MoveAround(-1,-1);
  1083.                     Closegraph;
  1084.                     CloseVirt;
  1085.                End.
  1086.  
  1087.     If you are smart, you already realized that this is slow... Again! Why ?
  1088.   Because you are moving 64000 bytes again, because of the virtual screen!
  1089.     So, what's the solution for the slowness ? Well, in my computer, there
  1090.   isn't !! But, in a good computer, you can try testing for the Vertical
  1091.   Retrace and clear and draw only when the electron beam is going up the
  1092.   screen... But, to clear and draw in a single retrace, you should avoid
  1093.   computing the movement of the stars, so you should use two arrays to store
  1094.   the before and after positions.
  1095.  
  1096.     Now, let's get to the real fun stuff... It was about time !!! This is
  1097.   getting to be the most boring article in 'The Mag'... As the matter of fact,
  1098.   this the most boring article of any mag!
  1099.     Ok, multi-speed scrolling! Well, stars that are at a greater distance from
  1100.   us tend to move slower relatively to us. So, you must compute the movement
  1101.   of the stars bearing in consideration the distance... But, because you don't
  1102.   have to add another variable that stores the distance, you can use the color
  1103.   variable, because a star that is farther from us is naturally less bright, so,
  1104.   the nearest the color is to 0, the slower it will move. The only thing that
  1105.   must be changed in the program is the procedure that computes the stars,
  1106.   the MoveStars procedure. It will became something like this:
  1107.  
  1108.                Procedure MoveStars(Ix,Iy:Integer);
  1109.                Var A:Integer;
  1110.                Begin
  1111.                     For A:=1 To 1000 Do
  1112.                     Begin
  1113.                          Stars[A].X:=Stars[A].X+Ix*(Stars[A].Color Div 4);
  1114.                          Stars[A].Y:=Stars[A].Y+Iy*(Stars[A].Color Div 4);
  1115.                          If Stars[A].X<0 Then Stars[A].X:=319;
  1116.                          If Stars[A].X>319 Then Stars[A].X:=0;
  1117.                          If Stars[A].Y<0 Then Stars[A].Y:=199;
  1118.                          If Stars[A].Y>199 Then Stars[A].Y:=0;
  1119.                     End;
  1120.                End;
  1121.  
  1122.     You add to the coordinate of the star a value computed taking in acount
  1123.   the distance, that is, the brightness of the star...
  1124.     This gives 4 different speeds (16 different brightnesses DIV 4)... You
  1125.   could improve to use real values, instead of integer, and then have a greater
  1126.   flexibility...
  1127.     So, get coding and improve this code, because, altough it is better
  1128.   than last issue's code it just plain _SUCKS_ ! :) Have fun... :)
  1129.  
  1130. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  1131.  
  1132.   7. Sprites Part I - Introduction
  1133.  
  1134.     This is the first of a series of articles that teaches you how to create
  1135.   and use your vey own Sprite Engine... Sprites are a very important part in
  1136.   coding games and some demos... They are the vital part of games like R-Type,
  1137.   Street-Fighter and all games like that.
  1138.     This will be more like a image handling tutorial, but sprites are just
  1139.   that, images that move (or not) on the screen. In the end of this first part,
  1140.   you will be able to get an image from the screen, how to save and load images
  1141.   from disk, and to put an image in the screen.
  1142.  
  1143.     7.1. Generating images
  1144.  
  1145.     This will teach you how to get an image from the screen.
  1146.     First of all, we need to know were to store it... The first think to come to
  1147.   mind is an array, but that isn't suitable to store an image, because we want
  1148.   to store images of different sizes, and an array has a fixed sized... So we
  1149.   need a structure whose size can be defined at run-time, rather than at
  1150.   compile time... So, who do you gonna call ? POINTERS !!!
  1151.     So, get 'The Mag', issue 7, for a complete explanation on how this
  1152.   particular way of handling pointers will work.
  1153.     So, the ideia is this:
  1154.  
  1155.                   1) Allocate the required space for the image
  1156.                   2) Get the image
  1157.  
  1158.     Let's start with number one... So, to allocate the space, we use the GetMem
  1159.   keyword, but we need to know how much space we want to allocate. Let's assume
  1160.   you are trying to make the GetImage procedure:
  1161.  
  1162.              Procedure GetImage(x1,y1,x2,y2:Word;Var Img:Pointer;Where:Word);
  1163.  
  1164.     This would get the image from (x1,y1) to (x2,y2) of page Where and store it
  1165.   in Img...
  1166.     Well, to store a pixel, you need a byte, well, to store a rectangular
  1167.   piece of image, you need x*y pixels, where x and y are the horizontal and
  1168.   vertical sizes, respectivelly. But, we also need to store the x and y sizes
  1169.   of the image, because we will need them to draw the image (to interpret the
  1170.   data store in the pointer, because that data won't be organized in a
  1171.   rectangule, but it will be stored as a line of bytes) and we need them also
  1172.   to deallocate the image, because we must know the size of the pointer to
  1173.   deallocate him... So, as the x and y are variables of type word, we need 2
  1174.   bytes for each, so we need 4 bytes for both. So, let's make the procedure:
  1175.  
  1176.              Procedure GetImage(x1,y1,x2,y2:Word;Var Img:Pointer;Where:Word);
  1177.              Var Dx,Dy:Word;
  1178.                  A,B:Word;
  1179.                  Segm,Offs:Word;
  1180.              Begin
  1181.                   { Allocate memory }
  1182.                   Dx:=Abs(x2-x1)+1;
  1183.                   Dy:=Abs(y2-y1)+1;
  1184.                   GetMem(Img,Dx*Dy+4);
  1185.                   { Gets the segment and offset of pointer, to access the }
  1186.                   { data indexed...                                       }
  1187.                   Segm:=Seg(Img^);
  1188.                   Offs:=Ofs(Img^);
  1189.                   { Stores x and y sizes of image }
  1190.                   Move(Dx,Mem[Segm:Offs],2);
  1191.                   Move(Dy,Mem[Segm:Offs+2],2);
  1192.                   { Store the image }
  1193.                   Offs:=Offs+4;
  1194.                   For A:=y1 to y2 Do
  1195.                     For B:=x1 to x2 Do
  1196.                     Begin
  1197.                          Mem[Segm:Offs]:=GetPixel(B,A,Where);
  1198.                          Inc(Offs);
  1199.                     End;
  1200.              End;
  1201.  
  1202.     Abs is a function that gives the absolute value of a number:
  1203.  
  1204.              Abs(5)  = 5
  1205.              Abs(-5) = 5
  1206.  
  1207.     GetPixel is a function defined in the Mode13h unit (given with this issue
  1208.   of 'The Mag'). It takes three parameters (x,y and Where), and it gives out
  1209.   the color number of the pixel at (x,y) of page Where.
  1210.     So, we have the procedure that gets an image and store it... As in every
  1211.   pointer, we need to deallocate it at some moment in time (even at the end
  1212.   of the program). So, before I forget, how to...
  1213.  
  1214.     7.2. Killing an image
  1215.  
  1216.     This is very simple... You just analise the x and y size of an image and
  1217.   deallocate the space given to the pointer.
  1218.     Code:
  1219.  
  1220.              Procedure KillImage(Var Img:Pointer);
  1221.              Var Dx,Dy:Word;
  1222.                  Segm,Offs:Word;
  1223.              Begin
  1224.                   { Get X and Y size of image }
  1225.                   Segm:=Seg(Img^);
  1226.                   Offs:=Ofs(Img^);
  1227.                   Move(Mem[Segm:Offs],Dx,2);
  1228.                   Move(Mem[Segm:Offs+2],Dy,2);
  1229.                   { Clear pointer }
  1230.                   FreeMem(Img,Dx*Dy+4);
  1231.              End;
  1232.  
  1233.     Easy, isn't it ?
  1234.     Let's move on... It is no use getting an image if you can't show it...
  1235.  
  1236.     7.3. Displaying an image
  1237.  
  1238.     Well, to display an image, you must go to the pointer and dump the data
  1239.   onto the screen... That's easy enough to do, and there are some ways to speed
  1240.   up that process.
  1241.     Let's image a 4x4 image, stored in thr Img pointer, and we want to place
  1242.   that image at some coordinates, (x,y).
  1243.  
  1244.   Img -> 04 00 04 00 FF FA A0 01 02 03 04 05 06 00 C0 30 20 10 EE 02
  1245.          ----- ----- ----------- ----------- ----------- -----------
  1246.          |     |              |           |           |           |
  1247.          |     |              |           |           |--------|  |
  1248.          |     |              |           |                    |  |
  1249.          |     |              |-----------|----- FF FA A0 01   |  |
  1250.          |     |                          |----- 02 03 04 05   |  |
  1251.          |     |                                 06 00 C0 30 __|  |
  1252.          |     |                                 21 10 EE 02 -----|
  1253.          |     Y Size
  1254.          |
  1255.          X size
  1256.  
  1257.     Did you understand the above scheme ? We must translate a linear batch
  1258.   of bytes into a rectangular one... So:
  1259.  
  1260.              Procedure PutImage(X,Y:Integer;Var Img:Pointer;Where:Word);
  1261.              Var Dx,Dy:Word;
  1262.                  A,B:Word;
  1263.                  Segm,Offs:Word;
  1264.              Begin
  1265.                   { Get X and Y size of image }
  1266.                   Segm:=Seg(Img^);
  1267.                   Offs:=Ofs(Img^);
  1268.                   Move(Mem[Segm:Offs],Dx,2);
  1269.                   Move(Mem[Segm:Offs+2],Dy,2);
  1270.                   { Draw the picture }
  1271.                   Offs:=Offs+4;
  1272.                   For A:=Y To Y+Dy-1 Do
  1273.                     For B:=X To X+Dx-1 Do
  1274.                     Begin
  1275.                          PutPixel(B,A,Mem[Segm:Offs],Where);
  1276.                          Inc(Offs);
  1277.                     End;
  1278.              End;
  1279.  
  1280.     Yupi !! We have a PutImage procedure... But let's improve it... If you
  1281.   look closely at the scheme, you know that in you can transfer a line of the
  1282.   image at one, using the move command... So replace:
  1283.  
  1284.                   For A:=Y To Y+Dy-1 Do
  1285.                     For B:=X To X+Dx-1 Do
  1286.                     Begin
  1287.                          PutPixel(B,A,Mem[Segm:Offs],Where);
  1288.                          Inc(Offs);
  1289.                     End;
  1290.  
  1291.     With:
  1292.  
  1293.                   For A:=Y To Y+Dy-1 Do
  1294.                   Begin
  1295.                        Move(Mem[Segm:Offs],Mem[Where:A*320+X],Dx);
  1296.                        Offs:=Offs+Dx;
  1297.                   End;
  1298.  
  1299.     There it is... A fast (Pascal thinking) routine to put images on the
  1300.   screen...
  1301.     Try to put an image in coordinates in a way the image goes off the screen...
  1302.   As you may see, the image wraps around the screen in the X direction. Well,
  1303.   this won't do for most games, so we must introduce:
  1304.  
  1305.     7.4. Clipping
  1306.  
  1307.     Well, the ideia behind clipping is quite simple... You verify if the
  1308.   coordinates of a certain pixel are out of the screen, and if they are, you
  1309.   simply don't place it... This is obviosly slower than the normal PutImage,
  1310.   and you can't put the entire line all at once in the screen, but sometimes
  1311.   it's more usefull... So, you define the variables:
  1312.  
  1313.                            MinX=0; MaxX=319;
  1314.                            MinY=0; MaxY=199;
  1315.  
  1316.     This is the drawing window... Making this definitions you gain flexibility,
  1317.   because you gain the ability to clip the images to a part of the screen, not
  1318.   only to all of the screen.
  1319.     So, adapting the first PutImage procedure:
  1320.  
  1321.              Procedure PutImage_C(X,Y:Integer;Var Img:Pointer;Where:Word);
  1322.              Var Dx,Dy:Word;
  1323.                  A,B:Word;
  1324.                  Segm,Offs:Word;
  1325.              Begin
  1326.                   { Get X and Y size of image }
  1327.                   Segm:=Seg(Img^);
  1328.                   Offs:=Ofs(Img^);
  1329.                   Move(Mem[Segm:Offs],Dx,2);
  1330.                   Move(Mem[Segm:Offs+2],Dy,2);
  1331.                   { Draw the picture }
  1332.                   Offs:=Offs+4;
  1333.                   A:=Y;
  1334.                   While (A<=Y+DY-1) And (A<MaxY) Do
  1335.                   Begin
  1336.                        B:=X;
  1337.                        While (B<=X+DX-1) And (B<MaxX) Do
  1338.                        Begin
  1339.                             If (X>=MinX) And (Y>=MinY) Then
  1340.                               PutPixel(B,A,Mem[Segm:Offs],Where);
  1341.                             Inc(Offs);
  1342.                             Inc(B);
  1343.                        End;
  1344.                        Inc(A);
  1345.                   End;
  1346.              End;
  1347.  
  1348.     We use a While cicle instead of a For cicle, because if you think a bit,
  1349.   notice that if an X value is larger than the maximum X value permited, then
  1350.   all the X values of that line are also out of bounds, so no use in testing
  1351.   them... And the same for the Y values, so the use the while cicles to test
  1352.   it. So, inside the loops, we only need to test if the coordinates are bigger
  1353.   than the minimum values...
  1354.     You should choose carefully which one of the routines (with or without
  1355.   clipping) to use in your program, because the routine without clipping is
  1356.   a lot faster and is most usefull if certain cases...
  1357.  
  1358.     7.5. Saving to the disk
  1359.  
  1360.     Sometimes, you can't generate all the images you want in your programs,
  1361.   so you must load them from disk. But, to load to the disk, you have to save
  1362.   it first...
  1363.     To do so, you have to choose a format. I usually use a quite simple one:
  1364.   four bytes with the x and y sizes, and then the bitmap information... This
  1365.   way you can save and load directly from and to the pointer.
  1366.     So, let's make the procedure:
  1367.  
  1368.              Procedure SaveImage(Var F:File;Img:Pointer);
  1369.              Var Dx,Dy:Word;
  1370.                  Segm,Offs:Word;
  1371.              Begin
  1372.                   { Get X and Y size of image }
  1373.                   Segm:=Seg(Img^);
  1374.                   Offs:=Ofs(Img^);
  1375.                   Move(Mem[Segm:Offs],Dx,2);
  1376.                   Move(Mem[Segm:Offs+2],Dy,2);
  1377.                   { Save the data }
  1378.                   BlockWrite(F,Img^,Dx*Dy+4);
  1379.              End;
  1380.  
  1381.     We assume the parameter F (of type file) is already an opened file for
  1382.   writing. Why don't we open the file to write and close it within the
  1383.   procedure ?
  1384.     Well, because you may want to save more than one picture in a file, and
  1385.   if you did so, you only would be able to save one image.
  1386.     Now, let's pass on to:
  1387.  
  1388.     7.6. Loading from the disk
  1389.  
  1390.     I'll don't even bother explaining the loading procedure... It is _SO_
  1391.   simple !! You read the size, and you get the memory for the pointer... Then,
  1392.   you just shoot the data to the pointer! Simple, isn't it ?
  1393.  
  1394.              Procedure LoadImage(Var F:File;Var Img:Pointer);
  1395.              Var Dx,Dy:Word;
  1396.                  Segm,Offs:Word;
  1397.              Begin
  1398.                   { Get X and Y size of image }
  1399.                   BlockRead(F,Dx,2);
  1400.                   BlockRead(F,Dy,2);
  1401.                   { Get the memory }
  1402.                   GetMem(Img,Dx*Dy+4);
  1403.                   { Store X and Y sizes }
  1404.                   Segm:=Seg(Img^);
  1405.                   Offs:=Ofs(Img^);
  1406.                   Move(Dx,Mem[Segm:Offs],2);
  1407.                   Move(Dy,Mem[Segm:Offs+2],2);
  1408.                   { Store the image }
  1409.                   Offs:=Offs+4;
  1410.                   BlockWrite(F,Mem[Segm:Offs],Dx*Dy);
  1411.              End;
  1412.  
  1413.     So, here ends the first part of the sprites tutorial... Hope you enjoyed.
  1414.   Just a note: I've put all the procedures given in this issue in an unit
  1415.   called Images. That unit will be further expanded in the next issues, so
  1416.   make sure you update it...
  1417.  
  1418. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  1419.  
  1420.   8. Graphics Part VI - Scrolling Part II
  1421.  
  1422.     As you may have gussed already, this is the continuation of last issue's
  1423.   graphics seccion...
  1424.     In this issue, we will delve into other forms of scrolling, more complex
  1425.   ones... Not more complicated, just more complex.
  1426.  
  1427.     8.1. Tile scrolling
  1428.  
  1429.     You know the Ultima games ? (of course you know them ! Everybody knows
  1430.   them !!)...
  1431.     Well, they use this type of scrolling... What's the ideia ? Think about
  1432.   this: imagine you wanted to do a game and you wanted to scroll around in a
  1433.   playfield made up of 10 full screens... Well, you know a screen uses 64000
  1434.   bytes, so 10 screens would use 640000 bytes ! That almost all base memory !
  1435.   And a game with 10 screens isn't that big !! One of my old games had a
  1436.   playfield with almost 500 screens !!!
  1437.     But, if you think for a while you will come to the conclusion that in so
  1438.   many screens some things are going to be repeated... Imagine that the
  1439.   playfield is a grassland, with some trees... Well, that's were the concept
  1440.   of tilling comes to action...
  1441.     You must have some sort of a map and some graphics... The map will tell
  1442.   which graphics go to which places... So, like a puzzle, you build the image
  1443.   of small tiles.
  1444.     I'll only explain this method in a simple way, because I'm intending to do
  1445.   a whole article on them soon, because there is so much to know about them...
  1446.     So, let's put this into practice... You already know how to read and display
  1447.   images, so you must only to use following procedure to display a certain
  1448.   part of the map:
  1449.  
  1450.              Procedure DispGeo(X,Y,DX,DY,Where:Word);
  1451.              Var A,B:Word;
  1452.              Begin
  1453.                   For A:=0 To DX-1 Do
  1454.                     For B:=0 To DY-1 Do
  1455.                       PutImage(A*16,B*16,GeoImages[GeoMap[X+A,Y+B]]^,Where);
  1456.              End;
  1457.  
  1458.     Looks confusing ? It isn't... I'll explain... This procedure displays in
  1459.   coordinates (0,0) of the page choosen by the Where parameter the zone of the
  1460.   map that goes from (X,Y) to (X+DX,Y+DY). Don't confuse the x and y
  1461.   coordinates of the screen (or virtual page) with the x and y coordinates
  1462.   of the map.
  1463.     The map should be stored in the GeoMap array (this can be loaded or
  1464.   generated by the program), and the images (the tiles) should be loaded to
  1465.   the GeoImages array of pointers... This can be done with the following
  1466.   procedure:
  1467.  
  1468.              Procedure LoadGeoImages(Filename:String);
  1469.              Var F:File;
  1470.                  Index:Word;
  1471.              Begin
  1472.                   Assign(F,Filename);
  1473.                   Reset(F,1);
  1474.                   Index:=1;
  1475.                   While Not Eof(F) Do
  1476.                   Begin
  1477.                        LoadImage(F,GeoImages[Index]);
  1478.                        Inc(Index);
  1479.                   End;
  1480.              End;
  1481.  
  1482.     This loads all images available in a file to an array called GeoImages.
  1483.     In the example I'm making, the tiles are 16x16 pixels... That is the
  1484.   reason of the multiplication for 16 in the DispGeo procedure.
  1485.     An example of a procedure that generates a GeoMap is:
  1486.  
  1487.              Procedure GenGeoMap;
  1488.              Var A,B:Word;
  1489.              Begin
  1490.                   For A:=0 To GeoMapSizeX Do
  1491.                     For B:=0 To GeoMapSizeY Do
  1492.                       GeoMap[A,B]:=Random(5)+1;
  1493.              End;
  1494.  
  1495.     This fills the GeoMap with random tiles, ranging from 1 to 5.
  1496.     Now, to scroll around this map, you just have to call the DispGeo procedure
  1497.   with different X and Y values (don't alter the Dx and Dy values, or else
  1498.   you'll get funny results on the screen).
  1499.     There is a test program that uses the above procedure with this mag...
  1500.   It is called ScrlGeo.Pas... It uses the file ScrlGeo.Img that stores the
  1501.   images of the trees.
  1502.     So, the basics to get you going is taught... Use this knowledge wisely,
  1503.   my child... :)
  1504.  
  1505.     7.2. Parallax scrolling
  1506.  
  1507.     Some computers (like the Amiga) have built-in circuits that handle parallax
  1508.   scrolling, but in the PC, you have to code yourself your parallax engine...
  1509.   But, what is parallax scrolling... Well, parallax scrolling is similar to
  1510.   what I have done with the starfield effect in this issue (see article 6).
  1511.     Objects that are further away from us appear to move slower, so you must
  1512.   scroll them at different times... What I'm going to teach is a combination
  1513.   of two scrolls... For example, check the Prllx01.Pas program... This scrolls
  1514.   a piece of land, with some water on the sides... It uses the theory of
  1515.   scrolling of the last issue.
  1516.     Now, check the Prllx02.Pas program... It is similar in most respects,
  1517.   differing only in the fact that it scrolls clouds...
  1518.     Now, let's combine the two together !
  1519.     As we want to make parallax scrolling, you must make sure that the clouds
  1520.   move faster than the land, so let's do it like this: while the land scrolls
  1521.   one pixel, the clouds scroll two pixels ! Then, for every frame, we just have
  1522.   to combine the two scrolls... To do so, we draw the land and then we draw
  1523.   the clouds, making sure that only the white parts of the cloud are drawn,
  1524.   not the black parts. To do so, we have to check each pixel of the image to
  1525.   put on top... So, we have to modify the CopyPage procedure... Here is the
  1526.   new one (the T stands for Transparency):
  1527.  
  1528.                 Procedure CopyPage_T(From,Too:Word);
  1529.                 Var Offs:Word;
  1530.                 Begin
  1531.                      For Offs:=0 To 63999 Do
  1532.                        If Mem[From:Offs]<>0 Then Mem[Too:Offs]:=Mem[From:Offs];
  1533.                 End;
  1534.  
  1535.     Then, you just alter the procedure that calls the scrolls, in a way that
  1536.   it scrolls two times the clouds before scrolling once the land... And voilá,
  1537.   you have parallax scrolling... It's all in the Prllx03.Pas file... This is
  1538.   _VERY_SLOW_, but it is only to demonstrate... In future issues I will teach
  1539.   you how to do this in assembler and that will _REALLY_ speed up that thing...
  1540.  
  1541.     7.3. Partial scrolls
  1542.  
  1543.     This final part talks about partial scrolls... That's an easy concept to
  1544.   grasp... To partially scroll anything, independent from the direction, the
  1545.   ideia is to move one line (or part of a line) at a time... I'll give you the
  1546.   procedures that do this, and you dissect them as you will:
  1547.  
  1548.              Procedure ScrollUp(x1,y1,x2,y2,Where:Word);
  1549.              Var A:Word;
  1550.              Begin
  1551.                   For A:=y1 To y2 Do
  1552.                     Move(Mem[Where:A*320+x1],Mem[Where:(A-1)*320+x1],x2-x1);
  1553.              End;
  1554.  
  1555.              Procedure ScrollDown(x1,y1,x2,y2,Where:Word);
  1556.              Var A:Word;
  1557.              Begin
  1558.                   For A:=y2 DownTo y1 Do
  1559.                     Move(Mem[Where:A*320+x1],Mem[Where:(A+1)*320+x1],x2-x1);
  1560.              End;
  1561.  
  1562.              Procedure ScrollLeft(x1,y1,x2,y2,Where:Word);
  1563.              Var A:Word;
  1564.              Begin
  1565.                   For A:=y1 To y1 Do
  1566.                     Move(Mem[Where:A*320+x1],Mem[Where:A*320+x1-1],x2-x1);
  1567.              End;
  1568.  
  1569.              Procedure ScrollRigth(x1,y1,x2,y2,Where:Word);
  1570.              Var A:Word;
  1571.              Begin
  1572.                   For A:=y1 To y1 Do
  1573.                     Move(Mem[Where:A*320+x1],Mem[Where:A*320+x1+1],x2-x1);
  1574.              End;
  1575.  
  1576.     I think this is fairly simple to understand... The ScrollLeft and
  1577.   ScrollRight procedures haven't changed much, but in full screen scrolls we
  1578.   could move the entire screen up and down with just one intruction, but with
  1579.   partial scrolls we must move it line by line...
  1580.     Well, this is the end of the scrolling saga... I think I've covered almost
  1581.   everything, except tile-scrolling, that will be discussed in detail a future
  1582.   issue...
  1583.  
  1584. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  1585.  
  1586.   9. Hints and Tips
  1587.  
  1588.                 *   - Begginners tip
  1589.                 **  - Medium tip
  1590.                 *** - Advanced tip
  1591.  
  1592.  
  1593.     - Logic operations on ilogic operands (**)
  1594.  
  1595.       Well, I'm loosing my brain thinking about something to put here... I can't
  1596.       remember nothing...
  1597.       Ok, I remember something... Did you knew you could do logical operation
  1598.       such as AND, OR and NOT with operands of any kind ?
  1599.       You may ask, how does this work ???? Well, like this... Imagine the
  1600.       internal (binary) representation of the number 41:
  1601.  
  1602.                         41 = 00101001 ;  Then you ANDit with number 1:
  1603.                          1 = 00000001 ;  The result is:
  1604.                              00000001 ;  He makes the logic corresponding with
  1605.  
  1606.       the logic tables I have given you... Similiarly:
  1607.  
  1608.       OR:                 NOT:
  1609.  
  1610.       00101001        NOT 00101001 =
  1611.    OR 00000010            11010110
  1612.     = 00101010
  1613.  
  1614.       This is quite usefull sometimes, because logic operations are much faster
  1615.       than aritmetic options... There are quite nifty tricks to do with this,
  1616.       but I'll leave that for other issue... :)
  1617.  
  1618. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
  1619.  
  1620.  10. Points of View
  1621.  
  1622.     Ooff !! I'm tired... Almost 80000 bytes this one !! That's 15000 more than
  1623.   the second larger issue...
  1624.     Well, what can I say in this issue's point of view ?
  1625.     I really don't know... I'll satrt by telling what I'm going to put in the
  1626.   next issue... I'll continue the Sprites series (talk about transparency,
  1627.   animation and movement), the Graphics Series (I'll talk about text in mode
  1628.   13h)... I'll also do part II of the 'Building a text adventure' tutorial
  1629.   (talking about the parser and basic commands). I'll also start a tutorial
  1630.   on 'How to make a program 100% in assembler'... And I'm thinking of making
  1631.   another article on effects coding... I think that is going to be another
  1632.   _LARGE_ issue ! :)
  1633.     I don't know when is issue 9 be ready, because I'm going into projects
  1634.   time at the university (couple of works in assembly, one in Modula 2 and
  1635.   another in C)... And also, I must study a bit (if I want to pass the
  1636.   semester alive :) Also, I'm working on a game (won't tell you anything about
  1637.   it !! It's a secret), I'm making a talker and a MUD, and also a demo (all
  1638.   I'm going to say about this one here is the name: Into The Shadows !! Neat,
  1639.   isn't it ?). I don't know were I'll get the time to do this all, but I'm
  1640.   going to try...
  1641.     Well, this points of view are sucking big time !! As all this issue...
  1642.     Ok, I'll leave you with a question ?
  1643.     Am I beginning to be more serious in 'The Mag' ? Am I growing old and
  1644.   less funnier ? Hope not... :) But I feel I'm not as a comediant as I used to
  1645.   be... Maybe I've run out of jokes... Or maybe I'm just tired (after all,
  1646.   80000 bytes !!!)... So, to give you some humor, here's a couple of jokes:
  1647.  
  1648.         How many Microsoft programmers are needed to screw a lightbulb ?
  1649.         None !! They just change the standart ! :))))
  1650.  
  1651.         'Who the hell in General Failure and why is he reading my disk ???'
  1652.  
  1653. -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x
  1654.  
  1655.  11. The adventures of Spellcaster, the rebel programmer of year 2018.
  1656.  
  1657.   Episode 8 - Suicide
  1658.  
  1659.     The upgrading of our jetcar was going well... We were trying to hook up a
  1660.   Durallium block to the front of it, and to do so we needed to increase the
  1661.   power of the engine.
  1662.   - Has anyone ever told you that you are insane ? - Deathripper asked me.
  1663.   - Yep... - I answered, without taking my eyes of the drone that was lifting
  1664.     the heavy block. - Am I cool or what ?
  1665.   - No, you are insane... You are a suicidal maniac...
  1666.   - Well, suicide is quite fun, if you look at it with a nice perspective - I
  1667.     replied, with a grim look in my face and a dark tone of voice.
  1668.   - As the matter of fact, I'm the crazy one, going after this psicho's plans
  1669.     like this... - Karl muttered to himself, kicking a bolt and looking at his
  1670.     sister, that was working on the engine of the craft.
  1671.   - Well, this "psycho", as you called me can't code jack-shit, - I said,
  1672.     looking at Kristie with hatred in his eyes, remembering what she said about
  1673.     him about a week ago. - but I was the one that made this thing possible...
  1674.   - Oh, let's all kneel at the feet of the Great Lord Spellcaster, Master of
  1675.     Assembly Coding and Ruler of Gourad Shading !! - Excalibur said, ironically.
  1676.   - Shut the hell up, Kristie... - I shouted, my voice echoing in the cold
  1677.     closed room. - You shouldn't talk of what you don't know... - I said, with
  1678.     a cold emontionless voice.
  1679.   - Why do you stand up to this piece of shit, Karl ??!!! - She asked, waving
  1680.     her arms frantically.
  1681.   - Well... He's got a point... All we ever do is say that he can't code,
  1682.     altough the only thing we used so far to destroy Comptel is his virus...
  1683.     We are beeing unfair...
  1684.   - You are ?! - I asked, surprised. - Yes, of course you are... - I continued,
  1685.     trying to hide the surprise in my voice.
  1686.   - WHAT ?! - Excalibur shouted. - ARE YOU PAYING HEED TO A GUY THAT LOOKS LIKE
  1687.     HE HAS COME FROM THE VISUAL BASIC KINDERGARTEN ?!!! - Her voice then
  1688.     changed to a more friendly tone, yet filled with anger. - Well, in that
  1689.     case I'm OUT of your stupid and suicidal plan...
  1690.   She got up from beneath the jetcar and she opened the door of the garage.
  1691.   The sunlight hurted my eyes, and I look at her perfect body's shadow, thinking
  1692.   of the reasons that make me fight with her, when I knew, deep in my heart
  1693.   that I loved her. She swang her head, making her black hair fly in the wind,
  1694.   and she look directly at me... I could be wrong, but in her eyes there was
  1695.   much more than just hatred... I just didn't knew what it was... Then she
  1696.   turned over again and she left the garage.
  1697.   - Well, Gundsen, it looks like we don't have a pilot for the jetcar... - I
  1698.     said in a sad voice.
  1699.   - Don't worry... She'll be back... She always does... And after all, her hate
  1700.     for William Gates is so deep in her that she can forget any other hatred.
  1701.   I stood there in silent for awhile. Then I broke the silence with a question:
  1702.   - Why does she hate Gates so much ?
  1703.   - I know why... But only she can tell you...
  1704.   The garage fell in silence again... I looked at Gundsen, and his eyes were
  1705.   staring at me, as he could read my thoughs. He said, smilling:
  1706.   - No, I don't think she hates you at all...
  1707.   And saying this, he also leaved the garage and I was left alone with my
  1708.   thoughs, wondering if my feelings for Kristie were indeed so deep and visible
  1709.   as it seemed...
  1710.  
  1711.  
  1712.                                              See you in the next issue
  1713.                                             Diogo "SpellCaster" Andrade